Add feature flag allowing guest kernel to run in domain 0.
authorIan.Campbell@xensource.com <Ian.Campbell@xensource.com>
Wed, 22 Feb 2006 19:11:23 +0000 (19:11 +0000)
committerIan.Campbell@xensource.com <Ian.Campbell@xensource.com>
Wed, 22 Feb 2006 19:11:23 +0000 (19:11 +0000)
To support this we give kernel GDT entries DPL=0 and use kernel
segment selectors with RPL=0. Xen will crunch these to ring 1 when
they are passed in. When a segment selector is used directly or placed
in a stack frame the guest OS is reponsible for crunching the RPL.

Signed-off-by: Ian Campbell <Ian.Campbell@XenSource.com>
linux-2.6-xen-sparse/arch/i386/kernel/head-xen.S
linux-2.6-xen-sparse/arch/i386/kernel/process-xen.c
linux-2.6-xen-sparse/arch/i386/mm/fault-xen.c
linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/segment.h
xen/arch/x86/domain.c
xen/arch/x86/x86_32/mm.c
xen/arch/x86/x86_64/mm.c
xen/include/asm-x86/desc.h
xen/include/public/version.h

index 61db92a16d85d4154656d6f8aa0e13c45a8c0c3a..a7cb4c8dd8a02ca6971afa55b616ee096d24ba08 100644 (file)
@@ -106,8 +106,8 @@ ENTRY(cpu_gdt_table)
        .quad 0x0000000000000000        /* 0x53 reserved */
        .quad 0x0000000000000000        /* 0x5b reserved */
 
-       .quad 0x00cfbb000000ffff        /* 0x60 kernel 4GB code at 0x00000000 */
-       .quad 0x00cfb3000000ffff        /* 0x68 kernel 4GB data at 0x00000000 */
+       .quad 0x00cf9b000000ffff        /* 0x60 kernel 4GB code at 0x00000000 */
+       .quad 0x00cf93000000ffff        /* 0x68 kernel 4GB data at 0x00000000 */
        .quad 0x00cffb000000ffff        /* 0x73 user 4GB code at 0x00000000 */
        .quad 0x00cff3000000ffff        /* 0x7b user 4GB data at 0x00000000 */
 
@@ -182,6 +182,7 @@ ENTRY(_stext)
        .ascii  ",FEATURES=writable_page_tables"
        .ascii           "|writable_descriptor_tables"
        .ascii           "|auto_translated_physmap"
+       .ascii           "|ring0_kernel"
 #ifdef CONFIG_X86_PAE
        .ascii  ",PAE=yes"
 #else
index 3f6e31b47227c1ff90b44cbd3390bd635d81c5ab..d46ed9305a1e6339c3b1a8ad437c01dd697673ad 100644 (file)
@@ -272,7 +272,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
        regs.xes = __USER_DS;
        regs.orig_eax = -1;
        regs.eip = (unsigned long) kernel_thread_helper;
-       regs.xcs = __KERNEL_CS;
+       regs.xcs = GET_KERNEL_CS();
        regs.eflags = X86_EFLAGS_IF | X86_EFLAGS_SF | X86_EFLAGS_PF | 0x2;
 
        /* Ok, create the new process.. */
index 08887a10e774aa94c0369e5a573c9dea4e0ea148..308c0bbe8ab72cbdff2625124035b44dfeb7afb0 100644 (file)
@@ -85,7 +85,7 @@ static inline unsigned long get_segment_eip(struct pt_regs *regs,
                return eip + (seg << 4);
        
        /* By far the most common cases. */
-       if (likely(seg == __USER_CS || seg == __KERNEL_CS))
+       if (likely(seg == __USER_CS || seg == GET_KERNEL_CS()))
                return eip;
 
        /* Check the segment exists, is within the current LDT/GDT size,
@@ -396,7 +396,7 @@ good_area:
        switch (error_code & 3) {
                default:        /* 3: write, present */
 #ifdef TEST_VERIFY_AREA
-                       if (regs->cs == KERNEL_CS)
+                       if (regs->cs == GET_KERNEL_CS())
                                printk("WP fault at %08lx\n", regs->eip);
 #endif
                        /* fall through */
index cb114d5dc74d0cc42c8af45221d450c93412d0eb..b736fbac7a2d281dc8eb48033584a3e3ac5ed781 100644 (file)
 #define GDT_ENTRY_KERNEL_BASE  12
 
 #define GDT_ENTRY_KERNEL_CS            (GDT_ENTRY_KERNEL_BASE + 0)
-#define __KERNEL_CS (GDT_ENTRY_KERNEL_CS * 8 + 1)
+#define __KERNEL_CS (GDT_ENTRY_KERNEL_CS * 8)
+#define GET_KERNEL_CS() (__KERNEL_CS | (xen_feature(XENFEAT_ring0_kernel)?0:1) )
 
 #define GDT_ENTRY_KERNEL_DS            (GDT_ENTRY_KERNEL_BASE + 1)
-#define __KERNEL_DS (GDT_ENTRY_KERNEL_DS * 8 + 1)
+#define __KERNEL_DS (GDT_ENTRY_KERNEL_DS * 8)
+#define GET_KERNEL_DS() (__KERNEL_DS | (xen_feature(XENFEAT_ring0_kernel)?0:1) )
 
 #define GDT_ENTRY_TSS                  (GDT_ENTRY_KERNEL_BASE + 4)
 #define GDT_ENTRY_LDT                  (GDT_ENTRY_KERNEL_BASE + 5)
index fd9ffd7530981efd6358c181187c56c186517213..21ef47f0ce79e226c176a86a3305776a19a2727c 100644 (file)
@@ -356,7 +356,8 @@ int arch_set_info_guest(
      */
     if ( !(c->flags & VGCF_HVM_GUEST) )
     {
-        if ( ((c->user_regs.ss & 3) == 0) ||
+        if ( !VALID_STACKSEL(c->user_regs.ss) ||
+             !VALID_STACKSEL(c->kernel_ss) ||
              !VALID_CODESEL(c->user_regs.cs) )
             return -EINVAL;
 
index 1f5da338ea6963cdd8d89ae8af50e16973158d71..2bcb57f8b4e87fc8ece193293321b0ba2b796c31 100644 (file)
@@ -223,7 +223,7 @@ long do_stack_switch(unsigned long ss, unsigned long esp)
     int nr = smp_processor_id();
     struct tss_struct *t = &init_tss[nr];
 
-    if ( (ss & 3) != 1 )
+    if ( !VALID_STACKSEL(ss) )
         return -EPERM;
 
     current->arch.guest_context.kernel_ss = ss;
@@ -239,6 +239,7 @@ int check_descriptor(struct desc_struct *d)
 {
     unsigned long base, limit;
     u32 a = d->a, b = d->b;
+    u16 cs = a>>16;
 
     /* A not-present descriptor will always fault, so is safe. */
     if ( !(b & _SEGMENT_P) ) 
@@ -251,7 +252,7 @@ int check_descriptor(struct desc_struct *d)
      * DPL 0 -- this would get the OS ring-0 privileges).
      */
     if ( (b & _SEGMENT_DPL) == 0 )
-        goto bad;
+        d->b = b = b | (0x01<<13); /* Force DPL == 1 */
 
     if ( !(b & _SEGMENT_S) )
     {
@@ -272,9 +273,17 @@ int check_descriptor(struct desc_struct *d)
             goto bad;
 
         /* Can't allow far jump to a Xen-private segment. */
-        if ( !VALID_CODESEL(a>>16) )
+        if ( !VALID_CODESEL(cs) )
             goto bad;
 
+        /*
+         * VALID_CODESEL might have fixed up the RPL for us. So be sure to
+         * update the descriptor.
+         *
+         */
+        d->a &= 0x0000ffff;
+        d->a |= cs<<16;
+
         /* Reserved bits must be zero. */
         if ( (b & 0xe0) != 0 )
             goto bad;
index 2d6625353623a1c885dad0b3df2559252ae47199..f783cce7e6eea846124e9b0b61ed89741db82c76 100644 (file)
@@ -292,6 +292,7 @@ long do_set_segment_base(unsigned int which, unsigned long base)
 int check_descriptor(struct desc_struct *d)
 {
     u32 a = d->a, b = d->b;
+    u16 cs = a>>16;
 
     /* A not-present descriptor will always fault, so is safe. */
     if ( !(b & _SEGMENT_P) ) 
@@ -314,9 +315,17 @@ int check_descriptor(struct desc_struct *d)
         goto bad;
 
     /* Can't allow far jump to a Xen-private segment. */
-    if ( !VALID_CODESEL(a>>16) )
+    if ( !VALID_CODESEL(cs) )
         goto bad;
 
+    /*
+     * VALID_CODESEL might have fixed up the RPL for us. So be sure to
+     * update the descriptor.
+     *
+     */
+    d->a &= 0x0000ffff;
+    d->a |= cs<<16;
+
     /* Reserved bits must be zero. */
     if ( (b & 0xe0) != 0 )
         goto bad;
index 6d45d0cb2b37829523f704bcc180961e6602e13d..793413f56acc328364718f1b316969c222d2e652 100644 (file)
 #define VALID_SEL(_s)                                                      \
     (((((_s)>>3) < FIRST_RESERVED_GDT_ENTRY) || ((_s)&4)) &&               \
      (((_s)&3) == GUEST_KERNEL_RPL))
-#define VALID_CODESEL(_s) ((_s) == FLAT_KERNEL_CS || VALID_SEL(_s))
+#define VALID_CODESEL(_s) ({                                               \
+    if ( ((_s) & 3) == 0 )                                                 \
+        (_s) |= GUEST_KERNEL_RPL;                                          \
+    (_s) == FLAT_KERNEL_CS || VALID_SEL(_s); })
+#define VALID_STACKSEL(_s) ({                                              \
+    if ( ((_s) & 3) == 0 )                                                 \
+        (_s) |= GUEST_KERNEL_RPL;                                          \
+    (_s) == FLAT_KERNEL_SS || VALID_SEL(_s); })
 
 /* These are bitmasks for the high 32 bits of a descriptor table entry. */
 #define _SEGMENT_TYPE    (15<< 8)
index 84020a8218caa5a07f6f910196c8b031cfc071f9..55c5e8d147440b77e92d0bbd3dfe92578319ca88 100644 (file)
@@ -51,6 +51,7 @@ typedef struct xen_feature_info {
 #define XENFEAT_writable_page_tables       0
 #define XENFEAT_writable_descriptor_tables 1
 #define XENFEAT_auto_translated_physmap    2
+#define XENFEAT_ring0_kernel               3
 
 #define XENFEAT_NR_SUBMAPS 1